package algorithm.color2w.thread;

import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author wjl <br/>
 * @version 1.0
 * @ClassName: ProducerAndConsumer
 * 固定容量的阻塞容器的实现
 * <br/>
 * @Description: TODO<br />
 * @date: 2020/1/17 10:06<br/>
 */
public class ProducerAndConsumer<T>{

    private Lock lock = new ReentrantLock();
    //return ConditionObject
    private Condition putCondition = lock.newCondition();
    private Condition getCondition = lock.newCondition();

    public final LinkedList<T> linkedList = new LinkedList();
    private int listSize = 0;
    public ProducerAndConsumer() {

    }

    //如果使用synchronized和notifyAll ，notifyAll就

    //put 和 get 的时候需要考虑到当前的容器容量是否已满或已空，如果是的话那么就要进行等待。
    public T get(){
        T t = null;
        try{
            lock.lock();
            /*此处使用while而不能用if的原因：
            * 启动了两个生产者进程，多个消费者进程，当多个消费者进程都处于阻塞状态的时候，
            * 一旦生产者signalALl()，多个消费者会继续执行await()后面的内容，
            * 生产者线程A，生产者线程B都被唤醒，A会pop出一个元素，如果此时list为空，B再pop的时候就会报错
            */
            while (0 == listSize){
                getCondition.await();
            }
            t = linkedList.pop();
            listSize --;
            putCondition.signalAll();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        return t;
    }


    public void put(T t){
        try{
            lock.lock();
            while (listSize == 10){
                putCondition.await();
            }
            linkedList.add(t);
            ++ listSize;
            getCondition.signalAll();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
//java.lang.IllegalMonitorStateException
//	at java.lang.Object.notifyAll(Native Method)
//	at algorithm.color2w.thread.ProducerAndConsumer.put(ProducerAndConsumer.java:61)
//	at algorithm.color2w.thread.ProducerAndConsumer.lambda$main$1(ProducerAndConsumer.java:86)
//	at java.lang.Thread.run(Thread.java:748)
    public static void main(String[] args) {
        ProducerAndConsumer<String> garbge = new ProducerAndConsumer<>();

        for (int i = 0; i < 100; i++){
            new Thread(() ->{
                for (int j = 0; j < 5; j++){
                    System.out.println(garbge.get());;
                }
            },"c"+i).start();
        }

        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        for (int i = 0; i < 2; i++){
            // 启动两个生产者进程
            new Thread(() ->{
                for (int j = 0; j < 25; j++){
                    garbge.put(Thread.currentThread().getName()+" "+j);
                }
            },"p"+i).start();
        }













    }
}
